﻿using System.Collections;
using UnityEngine;
using ScFramework.Core;
using System.Collections.Generic;
using System;
using Newtonsoft.Json;

public class FluidProcessSubmodule : SubPhysicsModule, IWaterDebug
{
    /// <summary>
    /// 绑定的生成器
    /// </summary>
    WaterFather parent;
    public static FluidProcessSubmodule instance;
    /// <summary>
    /// 水粒子集合
    /// </summary>
    public Dictionary<uint, WaterData> WaterDataDIC = new Dictionary<uint,WaterData>();
    public Dictionary<uint, GameObject> WaterParticleDIC = new Dictionary<uint, GameObject>();
    uint Createid;
    float alphaDistance;

    public override BelongingSystem GetSystemType => BelongingSystem.Fluid;
    void UniteAround(uint id, List<Tuple<uint, WaterData>>addlist)
    {
        int count = 0;
        for(int i = 0; i < addlist.Count; i++)
        {
            if (addlist[i].Item2.pointToNext==null&&Vector2.Distance(WaterDataDIC[id].pos, addlist[i].Item2.pos) <= alphaDistance)
            {
                addlist[i].Item2.pointToNext = WaterDataDIC[id];
                UniteAround(addlist[i].Item1, addlist);
            }
            else
            {
                count++;
            }
        }
        if (count == addlist.Count) return;

    }
    WaterData Find(WaterData data)
    {
        while (data != data.pointToNext)
        {
            data = data.pointToNext;
        }
        return data;
    }

    public override void CheckInstance()
    {
        List<Tuple<uint,WaterData>> addList = new List<Tuple<uint, WaterData>>();
        List<Tuple<uint, WaterData>> removeList = new List<Tuple<uint, WaterData>>();
        foreach (var x in WaterDataDIC)
        {
            if (posChecker(x.Value.pos ))
            {
                addList.Add(new Tuple<uint, WaterData>(x.Key,x.Value));
                x.Value.isNeedInstance = true;
            }
            else
            {
                removeList.Add(new Tuple<uint, WaterData>(x.Key, x.Value));
                x.Value.isNeedInstance = false;
            }
        }
        UniteAround(addList[0].Item1,addList);
        foreach (var x in addList)
        {
            foreach (var X in WaterDataDIC)
            {
                if (Find(x.Item2).isNeedInstance == false)
                {
                    break;
                }
                if (Vector2.Distance(x.Item2.pos, X.Value.pos) <= alphaDistance)
                {
                    Find(x.Item2).isNeedInstance = false;
                }
            } 
        }
        foreach(var x in addList)
        {
            if (Find(x.Item2).isNeedInstance)
            {
                GameObject obj;
                if (WaterParticleDIC.TryGetValue(x.Item1, out obj))
                {
                    continue;
                }
                else
                {
                    obj = ResourceManager.Instance.Instantiate(parent.root, parent.transform);
                    WaterParticleDIC.Add(x.Item1, obj);

                }
             }
        }


        foreach(var x in removeList)
        {
            GameObject obj;
            if(WaterParticleDIC.TryGetValue(x.Item1,out obj))
            {
                WaterParticleDIC.Remove(x.Item1);
                ObjectPool.Recycle(obj);
            }
        }
    }

    public override uint Create(ElementState state, Vector2 pos)
    {
        var obj = ResourceManager.Instance.Instantiate(parent.root, parent.transform);
        while (GetMetaData(Createid) != null) Createid++;
        uint id = Createid++;
        obj.GetComponent<MetaballParticle>().id = id;
        obj.transform.position = pos;
        WaterParticleDIC.Add(id, obj);
        WaterData data = new WaterData();
        data.elementState = state;
        data.blood = GetFixedInfo(state).initBlood;
        data.pos = pos;
        WaterDataDIC.Add(id,data);
        return id;
    }

    public override void Delete(uint id)
    {
        GameObject obj;
        if(WaterParticleDIC.TryGetValue(id, out obj))
        {
            ObjectPool.Recycle(obj);
        }
        else
        {
            Debug.LogError("你正在删除场上未加载的物体");
        }
    }

    public override object GetAllData()

    {
        List<WaterData> ans = new List<WaterData>();
        foreach(var x in WaterDataDIC.Values)
        {
            ans.Add(x);
        }
        return JsonUtil.Serialize(ans);
    }

    public override List<CollisionArgs> GetCollideInfo()
    {
        var temColliderInfos = new List<CollisionArgs>();
        foreach (var x in parent.colliderInfos)
        {
            temColliderInfos.Add(x);
        }
        parent.colliderInfos.Clear();
        return temColliderInfos;
    }
    public override BasicInfo GetInfo(uint id)
    {
        WaterData x;
        if (WaterDataDIC.TryGetValue(id,out x))
        {
            FixedInfo info = GetFixedInfo(x.elementState);
            int blood = x.blood;
            int defence = info.Defence;
            int magicdefence = info.MagicDefence;
            int sharpness = info.Sharpness;
            int mass = info.Mass;
            Vector3 pos = x.pos;
            return new BasicInfo(blood, defence, magicdefence, sharpness, mass, pos);
        }
        else
        {
            return null;
        }
    }

    public override void OnInit(object args)
    {
        base.OnInit(args);
        instance = this;
        FluidProcessDebuger._iWaterDebug = this;
        var obj = ResourceManager.Instance.Instantiate("Prefab/Fluid/WaterFather");
        parent = obj.GetComponent<WaterFather>();

        SysModule.Get<MapEvent>().RegisterHandler(MapEvent.MapCreate, onMapCreate);
        //SysModule.Get<MapEvent>().RegisterHandler(MapEvent.MapPack, onTilemapPack);
        SysModule.Get<MapEvent>().RegisterHandler(MapEvent.MapLoad, onTilemapLoad);
        SysModule.Get<MapEvent>().RegisterHandler(MapEvent.MapClear, onTilemapClear);

    }
    private EventArgs onMapCreate(object sender, EventArgs e)
    {
        var mapArgs = e as MapInstanceArgs;
        if (mapArgs.sys == BelongingSystem.Fluid)
            this.Create((ElementState)Enum.Parse(typeof(ElementState), mapArgs.name), mapArgs.pos);
        return null;
    }
    /*private EventArgs onTilemapPack(object sender, EventArgs e)
    {
        var mapArgs = e as MapInstanceArgs;
        if (mapArgs.sys == BelongingSystem.Fluid)
        {
            WaterData data = new WaterData { elementState = (ElementState)Enum.Parse(typeof(ElementState), mapArgs.name) , pos = mapArgs.pos};
            string str= JsonConvert.SerializeObject(data);
            return new MapPackArgs { data = str, sys = BelongingSystem.Fluid };
        }
        return null;
    }*/
    private EventArgs onTilemapLoad(object sender, EventArgs e)
    {
        var ee = e as MapLoadArgs;
        if(ee.sys == BelongingSystem.Fluid)
            SetAllData(ee.datas);
        return null;
    }

    private EventArgs onTilemapClear(object sender, EventArgs e)
    {
        SetAllData(null);
        return null;
    }
    public override void SetAllData(object datas)
    {
        var info = datas as string;

        List<WaterData> infodata;
        if (datas == null)
        {
            infodata = new List<WaterData>();
            /*
            WaterDataDIC.Clear();
            List<GameObject> removeLis = new List<GameObject>();
            foreach (var x in WaterParticleDIC)
            {
                removeLis.Add(x.Value);
            }
            WaterParticleDIC.Clear();
            foreach (var x in removeLis)
            {
                ObjectPool.Recycle(x);
            }
            return;*/
        }
        else infodata = JsonUtil.Deserialize<List<WaterData>>(info);
        Createid = 0;
        
        List<WaterData> waterDatas = new List<WaterData>();
        foreach (var x in infodata)
        {
            waterDatas.Add(x);
        }
        WaterDataDIC.Clear();
        List<GameObject> removeList = new List<GameObject>() ;
        foreach(var x in WaterParticleDIC)
        {
            removeList.Add(x.Value);
        }
        WaterParticleDIC.Clear();
        foreach(var x in removeList)
        {
            ObjectPool.Recycle(x);
        }
        foreach(var x in waterDatas)
        {
            var obj = ResourceManager.Instance.Instantiate(parent.root, parent.transform);
            while (GetMetaData(Createid) != null) Createid++;
            uint id = Createid++;
            obj.GetComponent<MetaballParticle>().id = id;
            WaterParticleDIC.Add(id, obj);
            obj.transform.position = x.pos;
            WaterDataDIC.Add(id,x);
        }
    }

    public override void SetInfo(uint id, BasicInfo info)
    {
        WaterData x;
        if (WaterDataDIC.TryGetValue(id, out x))
        {
            x.blood = info.Blood;
            x.pos = info.Position;
            WaterParticleDIC[id].transform.position = info.Position;
        }
        else
        {
            Debug.LogError($"流体id为{id}的物体未找到");
        }
    }
    public override List<uint> GetOverlapBox(Vector2 pos, Vector2 siz, float angle)
    {
        var list= Physics2D.OverlapBoxAll(pos, siz, angle,4);
        List<uint> ids = new List<uint>();
        foreach(var x in list)
        {
            ids.Add(x.gameObject.GetComponent<MetaballParticle>().id);
        }
        return ids;
    }


    public FixedInfo GetFixedInfo(ElementState ele)
    {
        FixedInfo fixedInfo = new FixedInfo();
        switch (ele)
        {
            case ElementState.water:
                fixedInfo.initBlood = 100;
                fixedInfo.Defence = 100;
                fixedInfo.MagicDefence = 100;
                fixedInfo.Sharpness = 1;
                fixedInfo.Mass = 1;
                break;
        }
        return fixedInfo;
    }
    WaterData GetMetaData(uint id)
    {
        if (WaterDataDIC.ContainsKey(id))
        {
            return WaterDataDIC[id];
        }
        else
        {
            return null;
        }

    }












#if DEBUG
    [DebugCmdType("流体数据")]
    public static class FluidProcessDebuger
    {
        public static IWaterDebug _iWaterDebug;
        [DebugCmd("生成填充器")]
        public static string SetSpawner()
        {
            if (_iWaterDebug == null)
            {
                return "Instance not settled";
            }
            return _iWaterDebug.SetSpawner();
        }


        [DebugCmd("id获取基础信息", "水珠id")]
        public static string Getbaseinfo(uint id)
        {
            if (_iWaterDebug == null)
            {
                return "Instance not settled";
            }
            return _iWaterDebug.Getinfo(id);
        }
       [DebugCmd("获取总体数据")]
        public static string GetAllData()
        {
            if (_iWaterDebug == null)
            {
                return "Instance not settled";
            }
            return _iWaterDebug.GetAllData();
        }
        [DebugCmd("应用总体数据","数据")]
        public static string SetAllData(string datas)
        {
            if (_iWaterDebug == null)
            {
                return "Instance not settled";
            }
            return _iWaterDebug.SetAllData(datas);
        }
        [DebugCmd("创建一组物体", "数量")]
        public static string Createe(int count)
        {
            if (_iWaterDebug == null)
            {
                return "Instance not Settled";
            }
            return _iWaterDebug.Createe(count);
        }
        /* [DebugCmd("创建物体", "id")]
         public static string Create(int count)
         {
             if (_iWaterDebug == null)
             {
                 return "Instance not Settled";
             }
             return _iWaterDebug.Create(count);
         }*/
        [DebugCmd("删除实体", "实体ID")]
        public static string DeleteEntity(uint id)
        {
            if (_iWaterDebug == null)
            {
                return "Instance not Settled";
            }
            return _iWaterDebug.Delete(id);
        }
        [DebugCmd("获得上一帧撞击信息")]
        public static string GetColliderInfo()
        {
            if (_iWaterDebug == null)
            {
                return "Instance not Settled";
            }
            return _iWaterDebug.GetColliderInfo();
        }
    }
    public override void OnDestroy()
    {
        base.OnDestroy();
        FluidProcessDebuger._iWaterDebug = null;
    }
    string IWaterDebug.Getinfo(uint id)
    {
        var data = this.GetInfo(id);
        return $"血量是：{data.Blood},防御是{data.Defence}，位置是{data.Position}";
    }

    string IWaterDebug.Createe(int count)
    {
        for (int i = 0; i < count; i++)
        {
            this.Create(ElementState.water, new Vector2(0, 0));
        }
        return "成功创建物体";
    }

    string IWaterDebug.Delete(uint id)
    {
        this.Delete(id);
        return $"成功删除{id}对应物体";
    }

    /*
     * public ElementState StressingState;
    public BelongingSystem StressingSystem;
    public uint StressingID;

    public ElementState StressedState;
    public BelongingSystem StressedSystem;
    public uint StressedID;

    public CollisionBasicInfo Info;*/
    string IWaterDebug.GetColliderInfo()
    {
        var datas = this.GetCollideInfo();
        string str = datas.Count.ToString() + "\n";
        foreach (var x in datas)
        {
            str += $"自身id：{x.StressingID},自身元素{x.StressingState},自身系统{x.StressingSystem}\n" +
                $"对方id{x.StressedID}，对方系统{x.StressedSystem}，对方元素{x.StressedState}\n" +
                $"碰撞力{(x.Info as CollisionForceInfo).Force},位置{(x.Info as CollisionForceInfo).WorldPos}\n";
        }
        return str;
    }

    string IWaterDebug.GetAllData()
    {
        return GetAllData() as string;
    }

    string IWaterDebug.SetAllData(string datas)
    {
        SetAllData(datas);
        return "重置所有物体";
    }

    string IWaterDebug.SetSpawner()
    {
        ResourceManager.Instance.Instantiate("Prefab/Fluid/Spawner");
        return "创建成功";

    }

    public override bool AddWorldForceAtLocalPotision(uint id, Vector2 localPosition, Vector2 worldForce)
    {
        throw new NotImplementedException();
    }
}
public interface IWaterDebug
{
    string Getinfo(uint id);
    string GetAllData();
    string Createe(int count);
    string Delete(uint id);
    string GetColliderInfo();
    string SetAllData(string datas);
    string SetSpawner();

}
#endif